package com.alexwan.nightnote.widget;

import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.alexwan.nightnote.R;
import com.nineoldandroids.view.ViewHelper;

/**
 * 侧边栏自定义布局
 * 
 * @author alexwan
 * 
 */
public class DragLayout extends FrameLayout {

	private boolean mIsShowShadow = true;
	// 触摸和手势操作
	private GestureDetectorCompat mGestureDetector;
	private ViewDragHelper mDragHelper;
	//
	private DragListener mDragListener;
	private int mRange;
	private int mWidth;
	private int mHeight;
	private int mMainLeft;
	private Context mContext;
	private ImageView mImageshadow;
	//侧滑栏布局
	private RelativeLayout mLeftLayout;
	//主页面布局
	private MyLinearLayout mNoteLinearLayout;
	//侧滑栏关闭和打开状态
	private Status mStatus = Status.Close;

	public DragLayout(Context context) {
		this(context, null);
	}

	public DragLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		this.mContext = context;
	}

	public DragLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mGestureDetector = new GestureDetectorCompat(context,
				new YScrollDetector());
		mDragHelper = ViewDragHelper.create(this, dragHelperCallback);
	}

	class YScrollDetector extends SimpleOnGestureListener {
		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,
				float dy) {
			return Math.abs(dy) <= Math.abs(dx);
		}
	}

	private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

		@Override
		public int clampViewPositionHorizontal(View child, int left, int dx) {
			if (mMainLeft + dx < 0) {
				return 0;
			} else if (mMainLeft + dx > mRange) {
				return mRange;
			} else {
				return left;
			}
		}

		@Override
		public boolean tryCaptureView(View child, int pointerId) {
			return true;
		}

		@Override
		public int getViewHorizontalDragRange(View child) {
			return mWidth;
		}

		@Override
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
			super.onViewReleased(releasedChild, xvel, yvel);
			if (xvel > 0) {
				open();
			} else if (xvel < 0) {
				close();
			} else if (releasedChild == mNoteLinearLayout
					&& mMainLeft > mRange * 0.3) {
				open();
			} else if (releasedChild == mLeftLayout && mMainLeft > mRange * 0.7) {
				open();
			} else {
				close();
			}
		}

		@Override
		public void onViewPositionChanged(View changedView, int left, int top,
				int dx, int dy) {
			if (changedView == mNoteLinearLayout) {
				mMainLeft = left;
			} else {
				mMainLeft = mMainLeft + left;
			}
			if (mMainLeft < 0) {
				mMainLeft = 0;
			} else if (mMainLeft > mRange) {
				mMainLeft = mRange;
			}

			if (mIsShowShadow) {
				mImageshadow.layout(mMainLeft, 0, mMainLeft + mWidth, mHeight);
			}
			if (changedView == mLeftLayout) {
				mLeftLayout.layout(0, 0, mWidth, mHeight);
				mNoteLinearLayout.layout(mMainLeft, 0, mMainLeft + mWidth,
						mHeight);
			}

			dispatchDragEvent(mMainLeft);
		}
	};

	public interface DragListener {
		public void onOpen();

		public void onClose();

		public void onDrag(float percent);
	}

	public void setDragListener(DragListener dragListener) {
		this.mDragListener = dragListener;
	}

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		if (mIsShowShadow) {
			mImageshadow = new ImageView(mContext);
			mImageshadow.setImageResource(R.drawable.shadow);
			LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
					LayoutParams.MATCH_PARENT);
			addView(mImageshadow, 1, lp);
		}
		mLeftLayout = (RelativeLayout) getChildAt(0);
		mNoteLinearLayout = (MyLinearLayout) getChildAt(mIsShowShadow ? 2
				: 1);
		mNoteLinearLayout.setDragLayout(this);
		mLeftLayout.setClickable(true);
		mNoteLinearLayout.setClickable(true);
	}

	public ViewGroup getVg_main() {
		return mNoteLinearLayout;
	}

	public ViewGroup getVg_left() {
		return mLeftLayout;
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mWidth = mLeftLayout.getMeasuredWidth();
		mHeight = mLeftLayout.getMeasuredHeight();
		mRange = (int) (mWidth * 0.6f);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		mLeftLayout.layout(0, 0, mWidth, mHeight);
		mNoteLinearLayout.layout(mMainLeft, 0, mMainLeft + mWidth, mHeight);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		return mDragHelper.shouldInterceptTouchEvent(ev)
				&& mGestureDetector.onTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent e) {
		try {
			mDragHelper.processTouchEvent(e);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return false;
	}

	private void dispatchDragEvent(int mainLeft) {
		if (mDragListener == null) {
			return;
		}
		float percent = mainLeft / (float) mRange;
		animateView(percent);
		mDragListener.onDrag(percent);
		Status lastStatus = mStatus;
		if (lastStatus != getStatus() && mStatus == Status.Close) {
			mDragListener.onClose();
		} else if (lastStatus != getStatus() && mStatus == Status.Open) {
			mDragListener.onOpen();
		}
	}

	private void animateView(float percent) {
		float f1 = 1 - percent * 0.3f;
		ViewHelper.setScaleX(mNoteLinearLayout, f1);
		ViewHelper.setScaleY(mNoteLinearLayout, f1);
		ViewHelper.setTranslationX(mLeftLayout, -mLeftLayout.getWidth() / 2.3f
				+ mLeftLayout.getWidth() / 2.3f * percent);
		ViewHelper.setScaleX(mLeftLayout, 0.5f + 0.5f * percent);
		ViewHelper.setScaleY(mLeftLayout, 0.5f + 0.5f * percent);
		ViewHelper.setAlpha(mLeftLayout, percent);
		if (mIsShowShadow) {
			ViewHelper.setScaleX(mImageshadow, f1 * 1.4f
					* (1 - percent * 0.12f));
			ViewHelper.setScaleY(mImageshadow, f1 * 1.85f
					* (1 - percent * 0.12f));
		}
		getBackground().setColorFilter(
				evaluate(percent, Color.BLACK, Color.TRANSPARENT),
				Mode.SRC_OVER);
	}

	private Integer evaluate(float fraction, Object startValue, Integer endValue) {
		int startInt = (Integer) startValue;
		int startA = (startInt >> 24) & 0xff;
		int startR = (startInt >> 16) & 0xff;
		int startG = (startInt >> 8) & 0xff;
		int startB = startInt & 0xff;
		int endInt = (Integer) endValue;
		int endA = (endInt >> 24) & 0xff;
		int endR = (endInt >> 16) & 0xff;
		int endG = (endInt >> 8) & 0xff;
		int endB = endInt & 0xff;
		return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
				| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
				| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
				| (int) ((startB + (int) (fraction * (endB - startB))));
	}

	@Override
	public void computeScroll() {
		if (mDragHelper.continueSettling(true)) {
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}

	public enum Status {
		Drag, Open, Close
	}

	public Status getStatus() {
		if (mMainLeft == 0) {
			mStatus = Status.Close;
		} else if (mMainLeft == mRange) {
			mStatus = Status.Open;
		} else {
			mStatus = Status.Drag;
		}
		return mStatus;
	}

	public void open() {
		open(true);
	}

	public void open(boolean animate) {
		if (animate) {
			if (mDragHelper.smoothSlideViewTo(mNoteLinearLayout, mRange, 0)) {
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			mNoteLinearLayout.layout(mRange, 0, mRange * 2, mHeight);
			dispatchDragEvent(mRange);
		}
	}

	public void close() {
		close(true);
	}

	public void close(boolean animate) {
		if (animate) {
			if (mDragHelper.smoothSlideViewTo(mNoteLinearLayout, 0, 0)) {
				ViewCompat.postInvalidateOnAnimation(this);
			}
		} else {
			mNoteLinearLayout.layout(0, 0, mWidth, mHeight);
			dispatchDragEvent(0);
		}
	}

}
